requests¶Our first port of call should be the documentation - take a look around the sections in the API Endpoint Reference.
You'll discover:
base_url for the API is https://api.spotify.com/v1various endpoints which accept GET requests, such as:
https://api.spotify.com/v1/recommendations
https://api.spotify.com/v1/artists/{id}
Looking at the detailed page of each of these endpoints, you'll see a list of the query parameters that can (or are required) be provided, as well as the need for authorization details to be provided in the header.
Again, requests will simplify this process for us.
import requests
#replace this with your current client_credentials access_token:
access_token = 'BQCHXEgma0DJzRDlxTeuGYnqT9cdUaW93bC3Nq90adobVSWMDjjcN40n5ZQ0EmYHPVePzp6TJPb3Svvyg24'
headers = {'Authorization': f'Bearer {access_token}'}
requests and assigned our token to access_tokenheaders dictionary, with this parameter:value pair:Authorization: Bearer [access_token]Notice that we had to do some work to get the value in the format the API requires (with Bearer before the access_token); this is mentioned in the API documentation but wasn't clear to me before Google came to the rescue.
base_url = 'https://api.spotify.com/v1'
endpoint = '/albums/'
identifier = '1To7kv722A8SpZF789MZy7'
full_url = f'{base_url}{endpoint}{identifier}'
the URL is in component parts and combined using an f-string; this will allow us to make further requests to different endpoints more easily
the value assigned to identifier is an album_id; these can be found at the end of the URL of any album page on the Spotify Web Player
response = requests.get(full_url, headers=headers)
data = response.json()
print(list(data.keys()), '\n')
print(data['name'])
['album_type', 'artists', 'available_markets', 'copyrights', 'external_ids', 'external_urls', 'genres', 'href', 'id', 'images', 'label', 'name', 'popularity', 'release_date', 'release_date_precision', 'total_tracks', 'tracks', 'type', 'uri'] MTV Unplugged In New York
.json() method on the Response object to convert the JSON data into equivalent Python data stuctureslist of .keys() in the resulting dictionaryname key from the dictionaryWe learned previously how JSON is made up of the following structures:
JSON datasets are often heavily nested; by this it's meant that we can expect to encounter instances of these data structures within others.
data['artists']
[{'external_urls': {'spotify': 'https://open.spotify.com/artist/6olE6TJLqED3rqDCT0FyPh'},
'href': 'https://api.spotify.com/v1/artists/6olE6TJLqED3rqDCT0FyPh',
'id': '6olE6TJLqED3rqDCT0FyPh',
'name': 'Nirvana',
'type': 'artist',
'uri': 'spotify:artist:6olE6TJLqED3rqDCT0FyPh'}]
data['artists'][0]['name']
Nirvana
data key is itself a list of dictionaries (in this case there is only one element in the list, but the structure means that several artists could be accomodated) print(data['artists'][0]['external_urls']['spotify'])
https://open.spotify.com/artist/6olE6TJLqED3rqDCT0FyPh
We'll be looking later on at how we can better access nested data returned by our API requests.
After running the repl you forked earlier, you can access the data dictionary via the console:

main.py, the data dictionary (and anything else imported or created) is in memoryrepl, the Python interpreter is already running, and we can enter Python commandsWith our request for data relating to a particular album, the URL itself (with the {id} at the end of the endpoint) was sufficient to specify what data we were requesting.
However, we often need to be more specific, and it it's often more appropariate for the API to be structured to deal with such requests through the use of query parameters.
Again, fear not - requests is here to make life easier for us.
params = {'q': 'waterfall', 'type': 'track'}
search_endpoint = '/search'
search_url = f'{base_url}{search_endpoint}'
search_response = requests.get(search_url, headers=headers, params=params)
parameter:value pairs to params/search endpoint with the base_url we defined previouslyparams dictionary as the params argument in the GET requestwaterfall_tracks = search_response.json()
print(list(waterfall_tracks.keys()))
print(list(waterfall_tracks['tracks'].keys()))
print(list(waterfall_tracks['tracks']['items'][0].keys()))
['tracks'] ['href', 'items', 'limit', 'next', 'offset', 'previous', 'total'] ['album', 'artists', 'available_markets', 'disc_number', 'duration_ms', 'explicit', 'external_ids', 'external_urls', 'href', 'id', 'is_local', 'name', 'popularity', 'preview_url', 'track_number', 'type', 'uri']
Again, we see that the returned data structure has a lot of nesting.
type wasn't a required value and so the returned dataset could also have contained albums, artists, etcitems value is a list of dictionaries, each containing data about a given trackAPIs will not typically return all items if there are a large number of matches; instead, further calls to the API will be required. You may also encounter limits on the frequency or volume of requests to an API or particular endpoint.
print(waterfall_tracks['tracks']['total'])
print(waterfall_tracks['tracks']['limit'])
print(waterfall_tracks['tracks']['next'])
97307 20 https://api.spotify.com/v1/search?query=waterfall&type=track&offset=20&limit=20
Spend some time using requests.get() to fetch data from endpoints listed under Albums, Artists, Browse, Search, and Tracks in the documentation; all of these can be done using the Client Credentials access_token you created earlier.
See if you can create some reuable functions, to do things such as:
access_token and a track id as argumentsaccess_token and a string of keywords as argumentsFor now, don't worry about automatically renewing the access_token or diving too deep into the nested data - we'll be looking at that later on.